﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.XPath;
using System.IO;

namespace trimmer
{

    class Processor
    {

        //int numTexts = 0;


        public void Process()
        {
            Console.WriteLine("Выхрючиватель 0.1");
            DateTime dt_start = DateTime.Now;

            DirectoryInfo di = new DirectoryInfo("./in");
            FileInfo[] Files = di.GetFiles();
            try
            {
                if (Directory.Exists("./out")) Directory.Delete("./out", true);
            }
            catch (Exception ex)
            {
                Console.WriteLine("./out :" + ex.Message);
            }
            try { Directory.CreateDirectory("./out"); }
            catch (Exception ex) { Console.WriteLine("./out :" + ex.Message); };


            foreach (FileInfo fi in Files)
            {
                ProcessFile(fi);
            }
            //global results


        }


        bool isNessInScope(string str)
        {
            str = str.ToLower();
            if (str.Contains("governess")) return false;
            if (str.Contains("witness")) return false;
            if (str.Contains("harness")) return false;
            if (str.Contains("patroness")) return false;
            if (str.Contains("baroness")) return false;
            if (str.Contains("marchioness")) return false;
            if (str.Contains("championess")) return false;
            if (str.Contains("lioness")) return false;
            return str.Contains("ness");
            //governess witness harness patroness baroness
        }

        void PrintLacune()
        { 

        }
        bool isPunc(string str)
        { 
                if (str.Length > 1) return false;
                if (str.Contains(".") ||str.Contains("!") || str.Contains("?")) return true;
            return false;
        }
        void ProcessContext(int left, int right, XmlNodeList nodes, TextWriter wr)
        {
            XmlDocument outDoc = new XmlDocument();
            XmlNode newNode = outDoc.CreateElement("context");
            string strOutBuffer = "";
            int numNesses = 0;
            List<string> roots = new List<string>();
            List<string> sems = new List<string>();
            bool rootsFound = false;
            bool semFound = false;

            for (int i = left; i <= right; i++)
            {

                string str = nodes[i].InnerText.Trim();
                if (isNessInScope(str))
                {
                    roots.Add(str.Substring(0, 3));
                    try
                    {
                        sems.Add(nodes[i].Attributes["sem"].Value);
                    }
                    catch (Exception) { }
                }


                //create set of sems and roots
            }
            /*
            bool isFirstDotReached = false;
            int newLeft = left;
            int newRight = right;
            //ness sentence bouns
            for (int i = left; i <= right; i++) //trimming uncomplete sentence at the end and at the beginiing
            {
                if (nodes[i].InnerText.Length==1)
                if (nodes[i].InnerText.Contains(".") || nodes[i].InnerText.Contains("!") || nodes[i].InnerText.Contains("?")
                    )
                {
                    
                    newRight = i;
                    if (!isFirstDotReached)
                    {
                        isFirstDotReached = true;
                        newLeft = i + 1;
                    }

                }

            }*/
            //left = newLeft;
           // right = newRight;
            List<int> nessSentenceLeftBounds = new List<int>();
            List<int> nessSentenceRightBounds = new List<int>();
            int lastDotPos = left;
            bool isNessSentenceStarted = false;
            //fining sentences
            for (int i = left; i <= right; i++) //trimming uncomplete sentence at the end and at the beginiing
            {
                if (isPunc(nodes[i].InnerText))
                {
                    lastDotPos = i;
                    if (isNessSentenceStarted)
                    {
                        isNessSentenceStarted = false;
                        nessSentenceRightBounds.Add(lastDotPos);
                    }
                }
                if (isNessInScope(nodes[i].InnerText))
                    if (!isNessSentenceStarted)
                    {
                        isNessSentenceStarted = true;
                        nessSentenceLeftBounds.Add(lastDotPos);
                        // Console.WriteLine("Found ness, remembering last dot pos= "+lastDotPos.ToString());
                    }
            }
            
         //   for (int i = 0; i < nessSentenceLeftBounds.Count; i++)
           //     Console.Write(nessSentenceLeftBounds[i].ToString() + " ");
            //Console.WriteLine();
            //for (int i = 0; i < nessSentenceRightBounds.Count; i++)
              //  Console.Write(nessSentenceRightBounds[i].ToString() + " ");
            //Console.WriteLine();

            //return;
                for (int i = left; i <= right; i++)
                {
                    if (!isPunc(nodes[i].InnerText))
                    {
                    if (nessSentenceRightBounds.Contains(i)) strOutBuffer += "</s>";
                    if (nessSentenceLeftBounds.Contains(i)) strOutBuffer += "<s>";
                    }
                    if (isNessInScope(nodes[i].InnerText))
                    {
                        numNesses++;
                        strOutBuffer += "<ness>" + nodes[i].OuterXml + "</ness> ";
                    }

                    else
                    {//roots
                        string lbr = "";
                        string rbr = "";
                        string tok = nodes[i].InnerText.Trim();
                        if (tok.Length > 3)
                            if (roots.Contains(tok.Substring(0, 3)))
                            {
                                rootsFound = true;
                                lbr = "<root>";
                                rbr = "</root>";
                            }
                        string sem = "###";
                        try { sem = nodes[i].Attributes["sem"].Value; }
                        catch { }
                        if (sems.Contains(sem))
                        {
                            semFound = true;
                            lbr = "<theme>" + lbr;
                            rbr = rbr + "</theme>";
                        }
                        if (nodes[i].InnerText.Contains("@@@"))
                            strOutBuffer += "\n";
                        else
                            strOutBuffer += lbr + nodes[i].OuterXml + rbr + " ";
                    }
                    if (isPunc(nodes[i].InnerText))
                    {
                    if (nessSentenceRightBounds.Contains(i)) strOutBuffer += "</s>";
                    if (nessSentenceLeftBounds.Contains(i)) strOutBuffer += "<s>";
                    }


                }
                //if (isNessSentenceStarted) nessSentenceRightBounds.Add(right);
                if (isNessSentenceStarted) strOutBuffer+="</s>";
                try
                {
                    newNode.InnerXml = strOutBuffer;
                }
                catch (Exception ex)
                {
                        Console.WriteLine(strOutBuffer);
                        throw ex;
                }
            //    Console.WriteLine(strOutBuffer);
                
            if (numNesses > 1)
            {
                XmlNode mult = outDoc.CreateElement("multiple");
                mult.AppendChild(newNode);
                newNode = mult;
            }
            if (rootsFound)
            {
                XmlNode mult = outDoc.CreateElement("word-formation");
                mult.AppendChild(newNode);
                newNode = mult;
            }
            wr.Write(newNode.OuterXml);
            wr.WriteLine("\n");

        }
        void ProcessFile(FileInfo fi)
        {
            Console.WriteLine("\nProcessing " + fi.Name);

            XmlDocument inDoc = new XmlDocument();
            inDoc.Load(fi.FullName);



            XmlNodeList nodes = inDoc.SelectNodes("//w");
            int lastNess = 0;
            int posLeftNessInContext = 0;
            int posLastContextRight = 0;

            int contextSize = 140;
            int nessCount = 0;

            // Queue<XmlNode> queue = new Queue<XmlNode>(2);
            //    XmlTextWriter wr = new XmlTextWriter("./out/" + fi.Name, Encoding.UTF8);

            TextWriter wr = new StreamWriter("./out/" + fi.Name);
            try
            {
                wr.WriteLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<text>");

                for (int i = 0; i < nodes.Count; i++)
                {
                    if ((i % 1000) == 0)
                    {
                        Console.WriteLine(i.ToString() + " of " + nodes.Count.ToString());
                    }
                    lastNess--;
                    if (lastNess < 0)
                    {
                        posLeftNessInContext = i;
                    }
                    if (isNessInScope(nodes[i].InnerText))
                    {
                        nessCount++;
                        lastNess = contextSize;
                        //increase queue
                    }
                    if (lastNess == 0)//it's time to flush queue
                    {
                        int posContextLeft = posLeftNessInContext - contextSize;
                        if (posContextLeft < 0) posContextLeft = 0;

                        //print lacune before context
                                            for (int k = posLastContextRight; k < posContextLeft; k++)
                                          {
                                            if (nodes[k].InnerText.Contains("@@@"))
                                              wr.WriteLine(); else
                                        wr.Write(nodes[k].OuterXml);
                                  }
                          wr.WriteLine("\n");
                        posLastContextRight = i + 1;

                        //print contexts


                        ProcessContext(posContextLeft, i, nodes, wr);
                        //  root.AppendChild(newNode);
                        //  root.InnerXml += "\n\n";
                    }



                    //Console.WriteLine(nodes[i].InnerText);

                }
                //print final part
                {
                    int posContextLeft = posLeftNessInContext - contextSize;
                    if (posContextLeft < 0) posContextLeft = 0;

                    if (lastNess > 0)
                    {

                        ProcessContext(posContextLeft, nodes.Count - 1, nodes, wr);
                    }
                    else //print last lacune
                        for (int k = posLastContextRight; k < nodes.Count; k++)
                        {
                            if (nodes[k].InnerText.Contains("@@@"))
                                wr.WriteLine();
                            else
                                wr.Write(nodes[k].OuterXml);
                        }
                }
                //XmlWriter wr = XmlWriter.Create("./out/"+fi.Name);


                //wr.Formatting = Formatting.None;
                //outDoc.WriteTo(wr);
                wr.WriteLine("</text>");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                wr.Close();
                return;
            }
            wr.Close();
            // remove all b,

        }// end processfile
    }

}
